package cn.haulon.util;

import java.util.*;

/**
 * 解放双手，降低工作量的自动sql条件封装
 *
 * @author Haulon
 */
@SuppressWarnings({"unused", "WeakerAccess"})
public class SqlTerm {

    private SqlTerm() {
    }

    // 条件集合
    private Map<String, Term> terms = new LinkedHashMap<>();

    public static SqlTerm me() {
        return new SqlTerm();
    }

    /**
     * order by 用法：Order.asc.by([字段名]);
     *
     * @author Haulon
     */
    public enum Order {
        /**
         * 升序
         */
        asc,

        /**
         * 降序
         */
        desc;

        /**
         * order by 可以写函数或字段名
         *
         * @param by 参数
         */
        public String by(String... by) {
            StringBuilder sb = new StringBuilder();
            for (String b : by) {
                if (sb.length() != 0)
                    sb.append(",");
                else
                    sb.append("order by").append(" ");
                sb.append(b).append(" ").append(this.name());
            }
            return sb.toString();
        }

    }

    /**
     * or 分隔符 之后的条件其实是以and相接 格式为or (.. and ..)
     */
    public Term or() {
        Term t = new Term();
        terms.put(UUID.randomUUID().toString(), t);
        return t;
    }

    /**
     * or 分隔符 之后的条件其实是以and相接 格式为or (.. and ..)
     *
     * @param key 标识，根据此参数获取当前or
     */
    public Term or(String key) {
        if (key == null || "".equals(key.trim())) {
            throw new RuntimeException("'OR's key cant be null");
        }
        Term t = terms.get(key);
        if (t == null) {
            t = new Term();
            terms.put(key, t);
        }
        return t;
    }

    /**
     * 清除所有条件
     */
    public void clear() {
        terms.clear();
    }

    /**
     * 去除or条件
     */
    public void remove(String key) {
        terms.remove(key);
    }

    /**
     * 单个条件，包含常用的关系
     *
     * @author Haulon
     */
    @SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
    public static class Term {
        private StringBuilder sb = new StringBuilder();
        private List<Object> values = new ArrayList<>();

        private Term() {
        }

        private int length() {
            return sb.length();
        }

        private void and(String strTerm, String column) {
            if (column == null || column.trim().length() == 0) {
                throw new RuntimeException("column cant be null");
            }
            if (sb.length() != 0)
                sb.append(" ").append("and").append(" ");
            sb.append(strTerm);
        }

        private void join(StringBuilder sb, Object... values) {
            if (sb != null) {
                int length = values.length;
                while (length-- > 0) {
                    if (sb.length() != 0)
                        sb.append(",");
                    sb.append("?");
                }
            }
            this.values.addAll(new ArrayList<>(Arrays.asList(values)));
        }

        /**
         * 自定义条件
         *
         * @param query  自定义条件
         * @param values 条件值
         */
        public Term and(String query, Object... values) {
            and(query, "query");
            join(null, values);
            return this;
        }

        /**
         * 等于条件
         *
         * @param column 字段名称
         * @param value  条件值
         */
        public Term equal(String column, Object value) {
            and(column + " = ?", column);
            values.add(value);
            return this;
        }

        /**
         * 等于条件，多个字段都与之相等
         *
         * @param value   条件值
         * @param columns 多个字段
         */
        public Term allEqual(Object value, String... columns) {
            for (String column : columns) {
                equal(column, value);
            }
            return this;
        }

        /**
         * 不等于条件
         *
         * @param column 字段名称
         * @param value  条件值
         */
        public Term notEqual(String column, Object value) {
            and(column + " <> ?", column);
            values.add(value);
            return this;
        }

        /**
         * 不等于条件，多个字段都与之不等
         *
         * @param value   条件值
         * @param columns 多个字段
         */
        public Term allNotEqual(Object value, String... columns) {
            for (String column : columns) {
                notEqual(column, value);
            }
            return this;
        }

        /**
         * 小于条件
         *
         * @param column 字段名称
         * @param value  条件值
         */
        public Term less(String column, Object value) {
            and(column + " < ?", column);
            values.add(value);
            return this;
        }

        /**
         * 小于条件，多个字段比其小
         *
         * @param value   条件值
         * @param columns 多个字段
         */
        public Term allLess(Object value, String... columns) {
            for (String column : columns) {
                less(column, value);
            }
            return this;
        }

        /**
         * 小于等于条件
         *
         * @param column 字段名称
         * @param value  条件值
         */
        public Term lessEqual(String column, Object value) {
            and(column + " <= ?", column);
            values.add(value);
            return this;
        }

        /**
         * 小于等于条件，多个字段小于或等于其
         *
         * @param value   条件值
         * @param columns 多个字段
         */
        public Term allLessEqual(Object value, String... columns) {
            for (String column : columns) {
                lessEqual(column, value);
            }
            return this;
        }

        /**
         * 大于条件
         *
         * @param column 字段名称
         * @param value  条件值
         */
        public Term greater(String column, Object value) {
            and(column + " > ?", column);
            values.add(value);
            return this;
        }

        /**
         * 大于条件，多个字段比其大
         *
         * @param value   条件值
         * @param columns 多个字段
         */
        public Term allGreater(Object value, String... columns) {
            for (String column : columns) {
                greater(column, value);
            }
            return this;
        }

        /**
         * 大于等于条件
         *
         * @param column 字段名称
         * @param value  条件值
         */
        public Term greaterEqual(String column, Object value) {
            and(column + " >= ?", column);
            values.add(value);
            return this;
        }

        /**
         * 大于等于条件，多个字段大于或等于其
         *
         * @param value   条件值
         * @param columns 多个字段
         */
        public Term allGreaterEqual(Object value, String... columns) {
            for (String column : columns) {
                greaterEqual(column, value);
            }
            return this;
        }

        /**
         * 介于条件（等同于>= and <=）
         *
         * @param column     字段名称
         * @param valueLeft  左条件值
         * @param valueRight 右条件值
         */
        public Term between(String column, Object valueLeft, Object valueRight) {
            and(column + " between ? and ?", column);
            values.add(valueLeft);
            values.add(valueRight);
            return this;
        }

        /**
         * 介于条件（等同于>= and <=），多个字段都介于左与右中间
         *
         * @param valueLeft  左条件值
         * @param valueRight 右条件值
         * @param columns    多个字段
         */
        public Term allBetween(Object valueLeft, Object valueRight,
                               String... columns) {
            for (String column : columns) {
                between(column, valueLeft, valueRight);
            }
            return this;
        }

        /**
         * 不介于条件（等同于<= or >=）
         *
         * @param column     字段名称
         * @param valueLeft  左条件值
         * @param valueRight 右条件值
         */
        public Term notBetween(String column, Object valueLeft,
                               Object valueRight) {
            and(column + " not between ? and ?", column);
            values.add(valueLeft);
            values.add(valueRight);
            return this;
        }

        /**
         * 不介于条件（等同于<= or >=），多个字段都不介于左与右中间
         *
         * @param valueLeft  左条件值
         * @param valueRight 右条件值
         * @param columns    多个字段
         */
        public Term allNotBetween(Object valueLeft, Object valueRight,
                                  String... columns) {
            for (String column : columns) {
                notBetween(column, valueLeft, valueRight);
            }
            return this;
        }

        /**
         * 属于条件
         *
         * @param column 字段名称
         * @param values 多个条件
         */
        public Term in(String column, Object... values) {
            StringBuilder sb = new StringBuilder();
            join(sb, values);
            and(column + " in(" + sb + ")", column);
            return this;
        }

        /**
         * 属于条件，多个字段都属于其中
         *
         * @param values  多个条件
         * @param columns 多个字段
         */
        public Term allIn(Object[] values, String... columns) {
            for (String column : columns) {
                in(column, values);
            }
            return this;
        }

        /**
         * 不属于条件
         *
         * @param column 字段名称
         * @param values 多个条件
         */
        public Term notIn(String column, Object... values) {
            StringBuilder sb = new StringBuilder();
            join(sb, values);
            and(column + " not in(" + sb + ")", column);
            return this;
        }

        /**
         * 不属于条件，多个字段都不属于其中
         *
         * @param values  多个条件
         * @param columns 多个字段
         */
        public Term allNotIn(Object[] values, String... columns) {
            for (String column : columns) {
                notIn(column, values);
            }
            return this;
        }

        /**
         * 为空条件
         *
         * @param column 字段名称
         */
        public Term isNull(String column) {
            and(column + " is null", column);
            return this;
        }

        /**
         * 为空条件，多个字段都为空
         *
         * @param columns 多个字段
         */
        public Term allIsNull(String... columns) {
            for (String column : columns) {
                isNull(column);
            }
            return this;
        }

        /**
         * 非空条件
         *
         * @param column 字段名称
         */
        public Term isNotNull(String column) {
            and(column + " is not null", column);
            return this;
        }

        /**
         * 非空条件，多个字段都非空
         *
         * @param columns 多个字段
         */
        public Term allIsNotNull(String... columns) {
            for (String column : columns) {
                isNotNull(column);
            }
            return this;
        }

        /**
         * like条件
         *
         * @param column 字段名称
         * @param value  条件值
         */
        public Term like(String column, Object value) {
            and(column + " like ?", column);
            values.add("%" + value.toString() + "%");
            return this;
        }

        /**
         * like条件，多个字段都与之类似
         *
         * @param value   条件值
         * @param columns 多个字段
         */
        public Term allLike(Object value, String... columns) {
            for (String column : columns) {
                like(column, value);
            }
            return this;
        }

        /**
         * like条件，此字段与多个条件类似
         *
         * @param column 字段名称
         * @param values 多个条件值
         */
        public Term likeAll(String column, Object... values) {
            for (Object value : values) {
                like(column, value);
            }
            return this;
        }

        public List<Object> getValues() {
            return values;
        }

        @Override
        public String toString() {
            return sb.toString();
        }

    }

    /**
     * 获取参数值
     */
    public List<Object> getValues() {
        List<Object> values = new ArrayList<>();
        for (Term term : terms.values()) {
            Collection<?> c = term.getValues();
            values.addAll(c);
        }
        return values;
    }

    /**
     * 获取参数值，并追加值
     */
    public List<Object> getValues(Object... otherValues) {
        List<Object> values = new ArrayList<>(Arrays.asList(otherValues));
        values.addAll(0, getValues());
        return values;
    }

    /**
     * 获取参数值，并在list之前追加值
     */
    public List<Object> getValuesFix(Object... otherValues) {
        List<Object> values = new ArrayList<>(Arrays.asList(otherValues));
        values.addAll(getValues());
        return values;
    }

    /**
     * 获取参数值
     */
    public Object[] getValuesToArray() {
        return getValues().toArray();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Term term : terms.values()) {
            if (sb.length() != 0) {
                sb.append(" ").append("or");
            }
            if (term.length() != 0) {
                sb.append(" ").append("(").append(term).append(")");
            }
        }
        return sb.toString();
    }
}